/*
 Xern Entity Relocation Network
 Copyright (C) 2011 Ronie Salgado <roniesalg@gmail.com>

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

#ifndef XERNP_PACKET_HPP
#define XERNP_PACKET_HPP

#include <boost/array.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "Xern/DataTypes.hpp"

namespace XernProtocol
{
	namespace posix_time = boost::posix_time;
	using namespace Xern;

	/**
	 * Xern Session Layer Protocol (XSLP) packet.
	 */
	class Packet
	{
	public:
		enum Flags
		{
			FL_NONE 	= 	   0, // No flags.
			FL_RELIABLE = (1<<0), // Packet is reliable
			FL_ACKS 	= (1<<1), // Packet contains acknowledges.
			FL_RESENT	= (1<<2), // Packet is resent
			FL_OPEN		= (1<<3), // Open session.
			FL_ACCEPT	= (1<<4), // Session accepted.
			FL_DENIED	= (1<<5), // Session denied.
			FL_CLOSE	= (1<<6), // Close session.
			FL_CHANNEL	= (1<<7), // Channel control.
		};

        static const int MAX_PACKET_SIZE = (1<<16) - 40; // Minimum IPv6 MTU.
        static const int MAX_PACKET_HEADER = 10; // Not counting extra header.

        Packet();
        ~Packet();

        /// Decodes the packet header, payload and appended acks.
        void DecodePacket();

        /// Writes the packet header.
        void WriteHeader();
        void UpdateHeader();

        /// Writes the packet payload.
        void WritePayload(size_t size, const void *data);

        /// Writes the appended acknowledges.
        void WriteAcks(size_t numacks, const u32 *acks);

        /// Packet flags
        u8 flags;

        /// Packet sequence number. Can be random.
        u32 sequenceNumber;

        /// Source host session id.
        u32 sourceSession;

        /// Destination host session id.
        u32 destinationSession;

        /// Session channel id, used for differential throttle.
        u8 channel;

        /// Packet sent time. Milliseconds since January 1st, 2000.
        u64 sentTime;

        /// Packet last sent time. (Not sent).
        posix_time::ptime lastSentTime;

        /// Packet size.
        u16 packetSize;

        /// Packet data.
        boost::array<u8, MAX_PACKET_SIZE> packetData;

        /// Payload size.
        u16 payloadSize;

        /// Payload data.
        u8 *payloadData;

        /// Appended acknowledge size.
        u8 ackCount;

        /// Appended acknowledges.
        u8 *ackData;

        /// Packet resend count. (Not sent).
        u8 resendCount;
	};
}; // namespace XernProtocol

#endif //XERNP_PACKET_HPP
